package com.ruge.tool.math;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

public class BigDecimalTool {
    public static final BigDecimal HUNDRED = new BigDecimal("100");
    public static final BigDecimal THOUSAND = new BigDecimal("1000");
    public static final BigDecimal ZERO_POINT_ZERO_ONE = new BigDecimal("0.01");
    public static final BigDecimal ZERO_POINT_ZERO_SIX = new BigDecimal("0.06");

    public static BigDecimal defaultIfNull(BigDecimal value, BigDecimal defaultValue) {
        return value == null ? defaultValue : value;
    }

    public static BigDecimal zeroIfNull(BigDecimal value) {
        return value == null ? BigDecimal.ZERO : value;
    }

    /**
     * 元转成整型的分
     *
     * @param v    元
     * @param mode 模式
     * @return 整型的分
     */
    public static Integer yuanToIntegerCent(BigDecimal v, RoundingMode mode) {
        if (v == null) {
            return null;
        }
        return yuanToCent(v, 0, mode).intValue();
    }

    /**
     * 元转成分
     *
     * @param v     元
     * @param scale 精度
     * @param mode  模式
     * @return 分
     */
    public static BigDecimal yuanToCent(BigDecimal v, int scale, RoundingMode mode) {
        if (v == null) {
            return null;
        }
        return v.multiply(HUNDRED).setScale(scale, mode);
    }

    /**
     * 取反
     *
     * @param v 取反的值
     * @return v为空返回null，不为空取反
     */
    public static BigDecimal negate(BigDecimal v) {
        return v == null ? null : v.negate();
    }

    /**
     * 取反
     *
     * @param v   取反的值
     * @param def 默认值
     * @return v为空返回默认值，不为空取反
     */
    public static BigDecimal defaultNegate(BigDecimal v, BigDecimal def) {
        return v == null ? def : v.negate();
    }

    /**
     * 取反
     *
     * @param v  取反的值
     * @param mc 处理参数
     * @return v为空返回null，不为空取反
     */
    public static BigDecimal negate(BigDecimal v, MathContext mc) {
        return v == null ? null : v.negate(mc);
    }

    /**
     * 取反
     *
     * @param v   取反的值
     * @param mc  处理参数
     * @param def 默认值
     * @return v为空返回默认值，不为空取反
     */
    public static BigDecimal defaultNegate(BigDecimal v, MathContext mc, BigDecimal def) {
        return v == null ? def : v.negate(mc);
    }

    /**
     * 求 newData 相对于 oldData 增长率
     *
     * @param newData 新值
     * @param oldData 旧值
     * @return 增长率
     */
    public static BigDecimal riseRate(BigDecimal newData, BigDecimal oldData) {
        if (newData == null) {
            return null;
        }
        if (oldData == null || BigDecimal.ZERO.compareTo(oldData) == 0) {
            return BigDecimal.ONE;
        }
        BigDecimal difference = newData.subtract(oldData);
        return difference.divide(oldData.abs(), 4, RoundingMode.HALF_UP);
    }

    /**
     * a+b，为空则置0
     *
     * @param a 被加数
     * @param b 加数
     * @return 和
     */
    public static BigDecimal addZeroIfNull(BigDecimal a, BigDecimal b) {
        return zeroIfNull(a).add(zeroIfNull(b));
    }

    /**
     * a-b，为空则置0
     *
     * @param a 被减数
     * @param b 减数
     * @return 差
     */
    public static BigDecimal subtractZeroIfNull(BigDecimal a, BigDecimal b) {
        return zeroIfNull(a).subtract(zeroIfNull(b));
    }

    /**
     * a 是否不等于 0
     *
     * @param a 对比值
     * @return a.compareTo(BigDecimal.ZERO) != 0 返回 true，否则返回false
     */
    public static boolean notEqualZero(BigDecimal a) {
        return !equalZero(a);
    }

    /**
     * a 是否等于 0
     *
     * @param a 对比值
     * @return a.compareTo(BigDecimal.ZERO) == 0 返回 true，否则返回false
     */
    public static boolean equalZero(BigDecimal a) {
        return equal(a, BigDecimal.ZERO);
    }

    /**
     * a 是否不等于 b
     *
     * @param a 对比值
     * @param b 对比值
     * @return a.compareTo(b) != 0 返回 true，否则返回false
     */
    public static boolean notEqual(BigDecimal a, BigDecimal b) {
        return !equal(a, b);
    }

    /**
     * a 是否等于 b
     *
     * @param a 对比值
     * @param b 对比值
     * @return a.compareTo(b) == 0 返回 true，否则返回false
     */
    public static boolean equal(BigDecimal a, BigDecimal b) {
        return (a == null && b == null) || (a != null && b != null && a.compareTo(b) == 0);
    }

    /**
     * 科学记数法
     *
     * @param bg {@link BigDecimal}
     *           入参 0.0000001
     *           出参 1E-7
     */
    public static String toString(BigDecimal bg) {
        return bg == null ? null : bg.toString();
    }

    /**
     * 不使用指数
     *
     * @param bg {@link BigDecimal}
     *           入参 0.0000001
     *           出参 0.0000001
     */
    public static String toPlainString(BigDecimal bg) {
        return bg == null ? null : bg.toPlainString();
    }

    /**
     * 工程记数法
     *
     * @param bg {@link BigDecimal}
     *           入参 0.0000001
     *           出参 100E-9
     */
    public static String toEngineeringString(BigDecimal bg) {
        return bg == null ? null : bg.toEngineeringString();
    }

    // 获取 BigDecimal 的小数位数
    public static int getDecimalPlaces(BigDecimal number) {
        // 去除尾部的零
        number = number.stripTrailingZeros();
        // 获取小数位数
        return number.scale();
    }

    // 判断两个 BigDecimal 是否相等
    public static boolean isEqual(BigDecimal num1, BigDecimal num2) {
        return num1.compareTo(num2) == 0;
    }

    /**
     * 判断是否为整数
     *
     * @param number
     * @return
     */
    public static boolean isInteger(BigDecimal number) {
        return number == null ? false : number.stripTrailingZeros().scale() == 0;
    }
}
